/*
 ******************************************************************************
 *  Java Signal Framework for routing java objects. 
 *  Copyright (C) 2008  Manuel Stahl (thymythos@web.de)
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 ****************************************************************************** 
 */
package org.tru42.signal.processors.io;

import gnu.io.CommPortIdentifier;
import gnu.io.RXTXCommDriver;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;

import java.io.IOException;
import java.io.OutputStream;

import org.tru42.signal.lang.ISignal;
import org.tru42.signal.lang.SObject;
import org.tru42.signal.lang.annotation.Sink;

public class RS232 extends SObject {

	private int baudrate = 9600;
	
	protected ISignal rxSignal;
	
	protected RXTXCommDriver driver;

	protected SerialPort commPort;

	protected InputStreamSignal streamSignal;
	
	protected OutputStream outStream;

	public class RS232StreamSignal extends InputStreamSignal {

		public RS232StreamSignal(SObject processor) {
			super(processor, "output");
		}

		@Override
		public void run() {
			int read;
			try {
				while(!Thread.interrupted()) {
					while(stream.available() == 0)
						Thread.sleep(100);
					
					if(stream.available() > 0 && (read = stream.read()) != -1)
						setValue(read);
				}
			} catch (IOException e) {
			} catch (InterruptedException intEx) {
			}
		}
		
	}
	

	public RS232() {
		super();

		streamSignal = (InputStreamSignal) getSignal("output");
		driver = new RXTXCommDriver();
		driver.initialize();
	}
	
	@Sink
	public void input(long timestamp, byte value) {
		if(outStream != null)
			try {
				outStream.write(value);
			} catch (IOException e) {
				e.printStackTrace();
			}
	}
	
	@Sink
	public void portName(long timestamp, String value) {
		openCommPort(value);
	}
	
	@Sink
	public void baudrate(long timestamp, Integer baud) {
		this.baudrate = baud;
		if(commPort == null) return;
		try {
			commPort.setBaudBase(baud);
		} catch (UnsupportedCommOperationException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}			
	}
	
	@Override
	protected void finalize() throws Throwable {
		closeCommPort();
		super.finalize();
	}

	protected void closeCommPort() {
		outStream = null;
		if(streamSignal.getThread() != null) {
			streamSignal.getThread().interrupt();
			try { streamSignal.getThread().join(); } catch (InterruptedException e) {}
		}
		
		if(commPort != null) {
			System.out.println("RS232 " + commPort.getName() + " closed");
			commPort.close();
			commPort = null;
		}
	}
	
	protected void openCommPort(String device) {
		closeCommPort();
		try {
			System.out.println("RS232 open " + device);
			commPort = (SerialPort)driver.getCommPort(device, CommPortIdentifier.PORT_SERIAL);
			if(commPort == null) return;
			commPort.setBaudBase(baudrate);
			streamSignal.setInputStream(commPort.getInputStream());
			outStream = commPort.getOutputStream();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void dispose() {
		closeCommPort();
		super.dispose();
	}
}
	
